import re
import json
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.sms.v20210111 import sms_client, models

from django.conf import settings

from django_redis import get_redis_connection


# pip3 install tencentcloud-sdk-python


class TencentSmsCode(object):
    """
    phone str
    code [str,str]
    tpl_id str
    """

    def __init__(self, telephone, code, tpl):
        self.telephone = telephone
        self.code = code
        self.tpl = tpl
        self.tpl_id = ''

    def __data(self, status, msg):
        """返回格式封装"""
        data = {
            "status": status,
            "msg": msg
        }
        return data

    def __check(self):
        """进行校验是否合法"""
        ret_telephone = self.__check_telephone()
        if not ret_telephone:
            data = self.__data(1001, '手机号格式不正确')
            return data
        # 进行校验是否有tpl
        ret_tpl = self.__check_tpl()
        if not ret_tpl:
            data = self.__data(1002, '模板不正确')
            return data
        # 验证码的生成 redis进行查询是否过期 redis的存储
        ret_code = self.__set_code()
        if not ret_code:
            data = self.__data(1003, '60秒只能发送1次')
            return data

    def sms_check(self):
        """
        正常发送
        """
        ret = self.__check()
        self.__send_msg()
        return ret

    def sms_check_celery(self):
        """
        celery进行异步发送
        :return:
        """
        ret = self.__check()
        from auc_celery.sms.tasks import send_sms
        # 执行任务
        tid = send_sms.delay(self.telephone, self.code, self.tpl)
        return ret

    def __send_msg(self):
        try:
            phone = '+86%s' % self.telephone
            cred = credential.Credential(settings.TENCENT_SECRET_ID, settings.TENCENT_SECRET_KEY)
            httpProfile = HttpProfile()
            httpProfile.endpoint = "sms.tencentcloudapi.com"

            clientProfile = ClientProfile()
            clientProfile.httpProfile = httpProfile
            client = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)

            req = models.SendSmsRequest()
            params = {
                "PhoneNumberSet": [phone, ],  # 手机号
                "SmsSdkAppId": settings.TENCENT_APP_ID,  # 应用AppId，v2要应用sdk/key，v3新增了密钥,取消了key
                "SignName": settings.TENCENT_SIGN,  # 签名的模版名称
                "TemplateId": self.tpl_id,  # 短信模板的id,str格式
                "TemplateParamSet": self.code  # 格式必须是 ["验证码",参数]  参数可以为空，具体看自己的模板要求
            }
            req.from_json_string(json.dumps(params))
            resp = client.SendSms(req)
            # print(resp.to_json_string())
            if resp.SendStatusSet[0].Fee == 1:
                return True
            return
        except TencentCloudSDKException as err:
            print('err', err)

    def __check_telephone(self):
        """
            手机号校验
            :param phone: 手机号
            :return: True/None
        """
        ret = re.match('^1[3-9][0-9]{9}$', self.telephone)
        if ret:
            return True
        return

    def __check_tpl(self):
        tpl = self.tpl
        # print('tpl:', tpl)
        tpl_id = settings.TENCENT_SMS_TEMPLATES.get(tpl)
        if tpl_id:
            # print('tpl_id', tpl_id)
            self.tpl_id = tpl_id
            return True
        return

    def __set_code(self):
        """
        生成验证码存放redis
        :param phone: 手机号
        :return:
        """
        # 生成code
        code = self.code[0]
        print(code)
        # 保存redis
        conn = get_redis_connection('sms_code')
        pipe = conn.pipeline()  # 创建管道
        pipe.multi()  # 开启批量操作  （事务，）
        #  # 后端倒计时校验 查看redis是否有，有抛异常
        init_code = conn.get('init_code_%s' % self.telephone)
        if init_code:
            return
            # 保存正常验证码
        pipe.set('sms_code_%s' % self.telephone, code, ex=60 * 60 * 24 * 14)
        # 保存倒计时码
        pipe.set('init_code_%s' % self.telephone, code, ex=60)
        pipe.execute()  # 批量执行了
        return code
